/*
 * Copyright 2001-2006 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.training.killerapp.store.xstream;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.training.killerapp.model.Page;
import com.training.killerapp.model.User;
import com.training.killerapp.store.memory.KillerAppMemoryStore;

/**
 * A Killer App data store backed by an file populated by XStream.
 * 
 * @since 1.0
 */
public class KillerAppXStreamStore
    extends KillerAppMemoryStore
{
    private XStream xstream;
    private File file;
    private boolean read;

    /**
     * Constructs an XStream implementation which persists entries in an
     * XML-based map.
     * 
     * @param file the file storing the Killer App's data.
     */
    public KillerAppXStreamStore()
    {
    	super();

        xstream = new XStream( new DomDriver() );
        xstream.alias( "user", User.class );
        xstream.alias( "page", Page.class );
    }

    /**
     * Returns the file that underlies this datastore.
     * @return the file that underlies this datastore.
     */
    public File getFile()
    {
        return file;
    }

    public int createPage( Page page, String ownerEmail )
    {
        read();

        int id = super.createPage( page, ownerEmail );

        persist();

        return id;
    }

    public String createUser( User user )
    {
        read();

        String email = super.createUser( user );

        persist();

        return email;
    }

    /**
     * Updates the given Page to the file, using the current ID of the object
     * to overwrite the existing value. The ID must be set.
     * 
     * @param page the Page entry to update
     * @see KillerAppMemoryStore#updatePage(Page)
     * @throws NullPointerException
     */
    public void updatePage( Page page )
    {
        read();

        super.updatePage( page );

        persist();
    }

    public void updateUser( User user )
    {
        read();

        super.updateUser( user );

        persist();
    }

    public void deleteUser( User user )
    {
        super.deleteUser( user );

        persist();
    }

    public Page getPage( int page )
    {
        // TODO: use plexus lifecycle to call "read" on load?
        read();

        return super.getPage( page );
    }

    public User getUser( String email )
    {
        read();

        return super.getUser( email );
    }

    public Collection getUserCollection()
    {
        read();

        return super.getUserCollection();
    }

    /**
     * Stores the current state of the memory store into the xml file,
     * marshaled by XStream.
     * 
     * @return true if persist was successful, false if not
     */
    protected boolean persist()
    {
    	String xml = xstream.toXML( pageStore );

    	try
    	{
    		FileWriter writer = new FileWriter( file );

    		writer.write( xml );
    		writer.flush();

	    	return true;
    	}
    	catch( IOException e )
    	{
    		return false;
    	}
    }

    /**
     * Reads the xml file and decodes using XStream to re-populate the
     * memory store.
     * 
     * @return true if read was successful, false if not
     */
    protected boolean read()
    {
        if( read )
        {
            return true;
        }

        try
    	{
    		if( !file.exists() || file.length() == 0 )
    		{
    			return read = true;
    		}

	    	FileReader reader = new FileReader( file );

	    	pageStore = (Map)xstream.fromXML( reader );

            int largestId = 0;
	    	for( Iterator iter = pageStore.entrySet().iterator(); iter.hasNext(); )
            {
	    	    Map.Entry entry = (Map.Entry)iter.next();

	    	    Page page = (Page)entry.getValue();
	    	    User user = page.getOwner();

                userStore.put( user.getEmail(), user );

	    	    int currentId = ((Integer)entry.getKey()).intValue();
                if( currentId > largestId )
                {
                    largestId = currentId;
                }
            }
            id = largestId;

	    	return read = true;
    	}
    	catch( FileNotFoundException e )
    	{
    		return false;
    	}
    }
}
